/***********************************************************************************************************
============================================================================================================
 Bits Download Manager
 http://www.codeplex.com/BITSDownloadMgr

 Component:BITSDownloadMgr.Jobs
 File Name:DirectoryCopyJobCreator.cs
 
 
============================================================================================================
 Copyright (C) 2004-2007 Microsoft Corporation

 This source is subject to the Microsoft Public License (Ms-PL).
 See http:www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
 All other rights reserved.

 THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
 OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
 LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR
 FITNESS FOR A PARTICULAR PURPOSE.
============================================================================================================
***********************************************************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using BitsDownloadMgr.Interop;
using BitsDownloadMgr.Jobs;
using System.Collections.ObjectModel;
namespace BitsDownloadMgr.Jobs
{
    /// <summary>
    /// Implementation of a job that copies entire folders.  
    /// </summary>
	public partial class DirectoryCopyJobCreator : Form, ICreateJob
	{
        /// <summary>
        /// Creates a new Directory Job Creator. 
        /// </summary>
		public DirectoryCopyJobCreator()
		{
			InitializeComponent();
		}

		private DirectoryCopyJobOptions _jobOptions = new DirectoryCopyJobOptions();

		private void browseForFolder(object sender, EventArgs e)
		{
			string initialFolder;
			string dialogTitle;
			TextBox targetTextBox;
			//check the sender for an initial path.  
			if (sender == browseSourceFolder)
			{
				targetTextBox = srcFolderPath;
				dialogTitle = "Select Source Directory";
			}
			else
			{
				targetTextBox = destFolderPath;
				dialogTitle = "Select Destination Directory";
			}
			initialFolder = targetTextBox.Text.Trim();

			//if there is nothing in the initial path, use the desktop.  
			if (initialFolder.Length == 0)
			{
				initialFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop);
			}

			//now that we have the initial folder, show the Folder Browse dialog;
			folderBrowserDialog.Description = dialogTitle;
			folderBrowserDialog.SelectedPath = initialFolder;
			if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
			{
				targetTextBox.Text = folderBrowserDialog.SelectedPath;
			}
		}

		#region ICreateJob Members

        /// <summary>
        /// Creates a new Directory Copy Job
        /// </summary>
        /// <param name="manager">Copy Manager for the job</param>
        /// <param name="ownerWindow">Parent window for any dialogs</param>
        /// <returns></returns>
		public CopyJob CreateJob(CopyManager manager, IWin32Window ownerWindow)
		{
			if (this.ShowDialog(ownerWindow) == DialogResult.OK)
			{
				DirectoryCopyJobUtility util
					= new DirectoryCopyJobUtility();
				//return util.CreateCopyJobFromFolder(
				//    manager, this.srcFolderPath.Text, 
				//    this.destFolderPath.Text, _jobOptions); 
                CopyJob newJob = util.CreateJobFromFolder(manager,
					this.srcFolderPath.Text,
					this.destFolderPath.Text,
					_jobOptions);
                if(newJob.GetFiles().Count == 0)
                {
                    //no files in the job ... 
                    MessageBox.Show("The copy job could not be created because no files were found in the target",
                        "Job Creation Failed", MessageBoxButtons.OK, MessageBoxIcon.Warning, 
                        MessageBoxDefaultButton.Button1, 
                        this.RightToLeftLayout?MessageBoxOptions.RightAlign & MessageBoxOptions.RtlReading:0);
                    return null; 
                }
                return newJob; 
			}
			else
			{
				//return a null job.  
				return null;
			}
		}

        /// <summary>
        /// Description of Job Creator
        /// </summary>
		public string Description
		{
			get { return "Directory Copy Job"; }
		}

        /// <summary>
        /// Help text
        /// </summary>
		public string HelpText
		{
			get { return "Creates a copy job that copies all files from a specified folder"; }
		}
		#endregion
	

		private void OKButton_Click(object sender, EventArgs e)
		{
			if (isValidJob())
			{
				_jobOptions.IncludeChildFolders = includeSubdirectoriesChk.Checked; 
				this.DialogResult = DialogResult.OK;
				return; 
			}
			else
			{
				return; 
			}
		}

		private bool isValidJob()
		{
			//some preliminary checks.  
			if (srcFolderPath.Text.Trim().Length == 0 || destFolderPath.Text.Trim().Length == 0)
			{
                MessageBox.Show("Please supply both source and destination folders", "Directory Copy Job", 
                    MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1,
                    this.RightToLeftLayout ? MessageBoxOptions.RightAlign & MessageBoxOptions.RtlReading : 0);

				return false ;
			}
			else if (!System.IO.Directory.Exists(srcFolderPath.Text))
			{
				MessageBox.Show("Source folder does not exist or is inaccessible", "Directory Copy Job", 
                    MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1,
                    this.RightToLeftLayout ? MessageBoxOptions.RightAlign & MessageBoxOptions.RtlReading : 0);
				return false;
			}
			else
			{
				return true;
			}
		
		}
		private void sourceValidating(object sender, CancelEventArgs e)
		{
	
		}

		private void DirectoryCopyJobCreator_Load(object sender, EventArgs e)
		{

		}

		private void cancelButton_Click(object sender, EventArgs e)
		{

		}

		private void OKButton_Validating(object sender, CancelEventArgs e)
		{

			
		}

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", 
            "CA1811:AvoidUncalledPrivateCode", Scope="type")]
		private class DirectoryCopyJobOptions
		{
			private bool _includeChildFolders;

			[Description("True to include all child folders")]
			public bool IncludeChildFolders
			{
				get { return _includeChildFolders; }
				set { _includeChildFolders = value; }
			}

			private bool _overwriteFiles;

			[Description("If true, existing files will be overwritten.  If false, files that already exist in the destination folder will not be added to the job")] 
			public bool OverwriteFiles
			{
				get { return _overwriteFiles; }
				set { _overwriteFiles = value; }
			}

			private int _threadCount;

			[Description("Number of threads to use for file and folder enumeration")]
			public int ThreadCount
			{
				get { return _threadCount;}
				set { _threadCount = value;}
			}


		}
		private class DirectoryCopyJobUtility
		{

			public DirectoryCopyJobUtility()
			{

			}
			private System.Collections.Generic.Queue<System.IO.DirectoryInfo> folderQueue
				= new System.Collections.Generic.Queue<System.IO.DirectoryInfo>();

            private CopyJob _activeJob;

            public CopyJob ActiveJob
            {
                get { return _activeJob; }
                set { _activeJob = value; }
            } 

			#region Folder Queue Management Code
			private void addFolderToQueue(System.IO.DirectoryInfo newFolder)
			{
				lock (folderQueue)
				{
					folderQueue.Enqueue(newFolder);
				}
			}

			private bool foldersInQueue
			{
				get
				{
					return folderQueue.Count > 0;
				}
			}

			private System.IO.DirectoryInfo getNextFolder()
			{
				lock (folderQueue)
				{
					return folderQueue.Dequeue();
				}
			}

			#endregion



			
			public CopyJob CreateJobFromFolder(CopyManager manager, string sourceFolder, string destFolder, DirectoryCopyJobOptions options)
			{
				//first, get the file list.  
				//in the future, we'll multithread this and add while the job gets started.  
				Collection<FileInfo> sourceFileList = new Collection<FileInfo>();
				sourceFolder = FileUtilities.NormalizeDirectoryPath(sourceFolder);
				destFolder = FileUtilities.NormalizeDirectoryPath(destFolder);
				try
				{
					System.IO.DirectoryInfo destDir = FileUtilities.GetDirectoryInfo(destFolder, true);
					System.IO.DirectoryInfo sourceDir = FileUtilities.GetDirectoryInfo(sourceFolder, false); 
					sourceFolder = sourceDir.FullName;
					//loop over the files 
					AddFolderFilesToList(sourceDir, destDir, sourceFileList, options.IncludeChildFolders);
				}
				catch (System.IO.DirectoryNotFoundException )
				{
					//TODO: Logic to handle folder not found.  
					throw;
				}
				try
				{
					CopyJob currentJob = manager.CreateJob("BITS Folder Copy", "Copying from " + sourceFolder, BitsJobType.Download, BitsJobPriority.High);
					currentJob.AddFiles(sourceFileList);
					return currentJob;
				}
				catch (System.IO.DirectoryNotFoundException)
				{
					//TODO: Logic to handle dest folder not found.  
					throw;
				}
			}

			/// <summary>
			/// Gets a list of FileInfo for a specified folder.
			/// </summary>
			/// <param name="sourceFolder">The source directory</param>
			/// <param name="destFolder">The target directory</param>
			/// <param name="options">The options for the copy job.</param>
			/// <returns></returns>
			private List<FileInfo> GetFolderFileList(System.IO.DirectoryInfo sourceFolder, 
				System.IO.DirectoryInfo destFolder, DirectoryCopyJobOptions options)
			{
                
				List<FileInfo> folderFileList = new List<FileInfo>();
				foreach (System.IO.FileInfo file in sourceFolder.GetFiles())
				{
					folderFileList.Add(new FileInfo(file.FullName, file.FullName.Replace(sourceFolder.FullName, destFolder.FullName)));
				}
				return folderFileList;
			}

			private void processFolder(System.IO.DirectoryInfo sourceFolder, System.IO.DirectoryInfo destFolder, DirectoryCopyJobOptions options)
			{
				//when multithreading ... add the folders first so that threads are kept busy.  
				AddChildFoldersToQueue(sourceFolder);

				
			}

			private void AddChildFoldersToQueue(System.IO.DirectoryInfo sourceDirectory)
			{
				System.IO.DirectoryInfo[] childFolders = sourceDirectory.GetDirectories();
				foreach (System.IO.DirectoryInfo childFolder in childFolders)
				{
					addFolderToQueue(childFolder);
				}
			}
			
			private void AddFolderFilesToList(System.IO.DirectoryInfo sourceDirectory,
				System.IO.DirectoryInfo destDirectory, Collection<FileInfo> fileList,
				bool includeSubdirectories)
			{
				foreach (System.IO.FileInfo file in sourceDirectory.GetFiles())
				{
					fileList.Add(new FileInfo(file.FullName, file.FullName.Replace(sourceDirectory.FullName, destDirectory.FullName)));
				}
				if (includeSubdirectories)
				{
					foreach (System.IO.DirectoryInfo childFolder in sourceDirectory.GetDirectories())
					{
						string destFolderPath = childFolder.FullName.Replace(sourceDirectory.FullName, destDirectory.FullName);
						System.IO.DirectoryInfo childDestDirectory = FileUtilities.GetDirectoryInfo(destFolderPath, true); 
						AddFolderFilesToList(childFolder, childDestDirectory, fileList);
					}
				}
			}
			private void AddFolderFilesToList(System.IO.DirectoryInfo sourceDirectory,
				System.IO.DirectoryInfo destDirectory, Collection<FileInfo> fileList)
			{
				AddFolderFilesToList(sourceDirectory, destDirectory, fileList, true);
			}



		}
}

	
}
